/** @file DataPacker.h
    @class DataPacker
    @brief Saves/loads commands to/from a replay file
*/
#ifndef _DataPacker_h_
#define _DataPacker_h_

#include <fstream>
#include <list>
#include <iostream>
#include "BitStream.h"
#include <sstream>
#include <time.h>
#include "Command.h"
#include "ViewCommand.h"
#include "MoveCommand.h"
#include "SpawnCommand.h"
#include "SynchCommand.h"
#include "DisconnectCommand.h"
#include "MovePlayerCommand.h"
#include "ShootCommand.h"

class DataPacker {
public:
	/**
	* @brief The save constructor, creates a unique name for the output stream
	*/
	DataPacker (void) {
		// Create unique name
		time_t seconds;
		seconds = time(NULL);

		// Int to string
		stringstream ss;
		ss << seconds << ".rep";
		mFileNameS = ss.str();
		mFileName = (char*) ss.str().c_str();
		
		mOfstream.open("replay.bin");
	}
	
	/**
	* @brief The load constructor
	*/
	DataPacker (string name) {
		mFileNameS = name;
		mFileName = (char *) name.c_str();
		mIfstream.open(mFileName);
	}
	
	/**
	* @brief The destructor
	*/
	virtual ~DataPacker (void) {
		// close streams
		if (mIfstream.is_open()) {
			mIfstream.close();
		} else if (mOfstream.is_open()) {
			mOfstream.close();
		}
	}
	
	/**
	* @brief Reads one frame of commands from the replay file and adds these to argument list
	*/
	void getCommands(list<Command*>* commands) {
		int i;
		int type;
		mIfstream.read((char*) &i, sizeof(int));
		for (int x = 0 ; x < i ; x++) {
			mIfstream.read((char*) &type, sizeof(int));
			Command *tmp;
			if (type == MOVECOMMAND) {
				tmp = new MoveCommand();
				tmp->load(mIfstream);
			} else if (type == VIEWCOMMAND) {
				tmp = new ViewCommand();
				tmp->load(mIfstream);
			} else if (type == SPAWNCOMMAND) {
				tmp = new SpawnCommand();
				tmp->load(mIfstream);
			} else if(type == DISCONNECTCOMMAND) {
				tmp = new DisconnectCommand();
				tmp->load(mIfstream);
			} else if (type == MOVEPLAYERCOMMAND){
				tmp = new MovePlayerCommand();
				tmp->load(mIfstream);
			} else if (type == SYNCHCOMMAND) {
				tmp = new SynchCommand();
				tmp->load(mIfstream);
			} else if(type == SHOOTCOMMAND) {
				tmp = new ShootCommand();
				tmp->load(mIfstream);
			}
			commands->push_back(tmp);
		}
	}
	
	/**
	* @brief Writes all commands in the argument list to its replay file
	*/
	void addCommands(list<Command*> &commands) {
		list<Command*>::iterator it;
		
		// Declaring the size of this commandlist
		int i = commands.size();
		mOfstream.write((char*) &i, sizeof(int));
		
		for (it = commands.begin() ; it != commands.end() ; it++) {
			(*it)->save(mOfstream);
		}
	}
	
	/**
	* @brief Returns the replay files name
	*/
	string getFileName() {
		return mFileNameS;
	}

private:
	/**
	* @brief Output file stream handling writing to replay file
	*/
	ofstream mOfstream;
	
	/**
	* @brief Replay file's name as a char*
	*/
	char* mFileName;
	
	/**
	* @brief Replay file's name as a string
	*/
	string mFileNameS;
	
	/**
	* @brief Input file stream handling reading from replay file
	*/
	ifstream mIfstream;
};

#endif